#pragma once

#include<iostream>
#include"thread.hpp"
#include"lockGuard.hpp"
#include<unistd.h>
#include<vector>
#include<queue>
#include<cstring>
#include"log.hpp"
const int g_thread_num=3;
//本质是：生产消费模型
template<class T>
class ThreadPool
{
public:
    pthread_mutex_t* getMutex()
    {
        return &lock;
    }
    bool isEmpty()
    {
        return task_queue_.empty();
    }
    void waitCond()
    {
        pthread_cond_wait(&cond,&lock);//调用释放锁，成功返回再加锁
    }
    T getTask()
    {
        T t=task_queue_.front();
        task_queue_.pop();
        return t;
    }
public:
    ThreadPool(int thread_num=g_thread_num)//初始化列表是初始化，代码块是赋值，此时代码块内至少空间已经有了
    :num_(thread_num)
    {
        pthread_mutex_init(&lock,nullptr);
        pthread_cond_init(&cond,nullptr);
        for(int i=0;i<num_;i++)
        {
            threads_.push_back(new Thread(i+1,routine,this));
        }
        
    }
    //1.run()
    void run()
    {
        for(auto& iter:threads_)
        {
            iter->start();
            //std::cout<<iter->name()<<"启动成功"<<std::endl;
            logMessage(NORMAL,"%s %s",iter->name().c_str(),"启动成功");
        }
    }
    //消费过程势必要访问类内的task_queue_去拿任务，但static无法使用类内成员属性和方法
    //解决方法：传递this指针拿到整体对象，通过函数方法拿到类内对象
    static void* routine(void* args)
    {
        ThreadData* td=(ThreadData*)args;
        ThreadPool<T>*tp=(ThreadPool<T>*)td->args_;
        while(true)
        {
            //lock
            //如果任务队列是空，等待
            //unlock
            //处理任务
            T task;
            {
                lockGuard lockguard(tp->getMutex());
                while(tp->isEmpty())tp->waitCond();
                //读取任务
                task=tp->getTask();//任务队列是共享的->将任务从共享拿到自己的私有空间
            }
            task(td->name_);
        }
    }
    //2.pushTask()
    void pushTask(const T& task)
    {
        lockGuard lockguard(&lock);
        task_queue_.push(task);
        //可能一个线程在放任务的时候，有若干给线程特定的同步竞争方式从任务队列中拿任务，
        //所以要保证安全问题（加锁）
        pthread_cond_signal(&cond);//未生产前，因为加锁，线程池里线程会休眠，所以生产进来后要唤醒一个线程
    }
    ~ThreadPool()
    {
        for(auto & iter:threads_)
        {
            iter->join();//释放线程资源
            delete iter;//释放堆上创建的对象
        }
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }

private:
    std::vector<Thread*> threads_;
    int num_;
    std::queue<T> task_queue_;
    pthread_mutex_t lock;
    pthread_cond_t cond;
};